From e6277d3b82440168e073bc83bf10fceb76d63995 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 10 Jan 2011 03:31:35 +0100 Subject: [PATCH] Add gtk_style_context_cancel_animations() This function takes a region ID and cancels all animations on or beneath that region (as in push/pop_animatable_region). First user of this is GtkWidget itself, so unmapped widgets have looping animations cancelled. Fixes bug #638119, reported by Jesse van den Kieboom. --- docs/reference/gtk/gtk3-sections.txt | 1 + gtk/gtk.symbols | 1 + gtk/gtkstylecontext.c | 72 ++++++++++++++++++++++++---- gtk/gtkstylecontext.h | 3 ++ gtk/gtkwidget.c | 3 ++ 5 files changed, 71 insertions(+), 9 deletions(-) diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index 3ae7fa8066..16372a5767 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -5547,6 +5547,7 @@ gtk_style_context_lookup_icon_set gtk_style_context_notify_state_change gtk_style_context_pop_animatable_region gtk_style_context_push_animatable_region +gtk_style_context_cancel_animations gtk_style_context_remove_provider gtk_style_context_remove_provider_for_screen gtk_style_context_reset_widgets diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 919ddd4a54..ead590e1a0 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -2461,6 +2461,7 @@ gtk_style_context_add_class gtk_style_context_add_provider gtk_style_context_add_provider_for_screen gtk_style_context_add_region +gtk_style_context_cancel_animations gtk_style_context_get gtk_style_context_get_background_color gtk_style_context_get_border diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index 162c97136c..3d1b0aa530 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -454,6 +454,12 @@ struct AnimationInfo GtkTimeline *timeline; gpointer region_id; + + /* Region stack (until region_id) at the time of + * rendering, this is used for nested cancellation. + */ + GSList *parent_regions; + GdkWindow *window; GtkStateType state; gboolean target_value; @@ -749,6 +755,7 @@ animation_info_free (AnimationInfo *info) cairo_region_destroy (info->invalidation_region); g_array_free (info->rectangles, TRUE); + g_slist_free (info->parent_regions); g_slice_free (AnimationInfo, info); } @@ -1572,7 +1579,6 @@ context_has_animatable_region (GtkStyleContext *context, gpointer region_id) { GtkStyleContextPrivate *priv; - GSList *r; /* NULL region_id means everything * rendered through the style context @@ -1581,14 +1587,7 @@ context_has_animatable_region (GtkStyleContext *context, return TRUE; priv = context->priv; - - for (r = priv->animation_regions; r; r = r->next) - { - if (r->data == region_id) - return TRUE; - } - - return FALSE; + return g_slist_find (priv->animation_regions, region_id) != NULL; } /** @@ -2919,6 +2918,53 @@ gtk_style_context_notify_state_change (GtkStyleContext *context, _gtk_animation_description_unref (desc); } +/** + * gtk_style_context_cancel_animations: + * @context: a #GtkStyleContext + * @region_id: (allow-none): animatable region to stop, or %NULL. + * See gtk_style_context_push_animatable_region() + * + * Stops all running animations for @region_id and all animatable + * regions underneath. + * + * A %NULL @region_id will stop all ongoing animations in @context, + * when dealing with a #GtkStyleContext obtained through + * gtk_widget_get_style_context(), this is normally done for you + * in all circumstances you would expect all widget to be stopped, + * so this should be only used in complex widgets with different + * animatable regions. + * + * Since: 3.0 + **/ +void +gtk_style_context_cancel_animations (GtkStyleContext *context, + gpointer region_id) +{ + GtkStyleContextPrivate *priv; + AnimationInfo *info; + GSList *l, *node; + + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); + + priv = context->priv; + l = priv->animations; + + while (l) + { + info = l->data; + node = l; + l = l->next; + + if (!region_id || + info->region_id == region_id || + g_slist_find (info->parent_regions, region_id)) + { + priv->animations = g_slist_remove (priv->animations, info); + animation_info_free (info); + } + } +} + /** * gtk_style_context_push_animatable_region: * @context: a #GtkStyleContext @@ -3096,6 +3142,14 @@ store_animation_region (GtkStyleContext *context, rect.height = (gint) height; g_array_append_val (info->rectangles, rect); + + if (!info->parent_regions) + { + GSList *parent_regions; + + parent_regions = g_slist_find (priv->animation_regions, info->region_id); + info->parent_regions = g_slist_copy (parent_regions); + } } } } diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h index ab9be702e8..ceedc529c0 100644 --- a/gtk/gtkstylecontext.h +++ b/gtk/gtkstylecontext.h @@ -522,6 +522,9 @@ void gtk_style_context_notify_state_change (GtkStyleContext *context, gpointer region_id, GtkStateType state, gboolean state_value); +void gtk_style_context_cancel_animations (GtkStyleContext *context, + gpointer region_id); + void gtk_style_context_push_animatable_region (GtkStyleContext *context, gpointer region_id); void gtk_style_context_pop_animatable_region (GtkStyleContext *context); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index b7c3141d0d..f0c56b4361 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -4191,6 +4191,9 @@ gtk_widget_unmap (GtkWidget *widget) g_signal_emit (widget, widget_signals[UNMAP], 0); gtk_widget_pop_verify_invariants (widget); + + if (priv->context) + gtk_style_context_cancel_animations (priv->context, NULL); } } -- 2.30.2